﻿#include "pch.h"

CIdtInfWrapper::CIdtInfWrapper()
{
    memset((void *)this, 0, sizeof(CIdtInfWrapper));
}

void CIdtInfWrapper::printSelf(char *captionUpper, int32_t)
{
    char caption[1024];
    sprintf(caption, "%s:%s", captionUpper, "CIdtInfWrapper");
    print4x(this, sizeof(CIdtInfWrapper), caption);
    if (this->head)
    {
        sprintf(caption, "%s:%s", captionUpper, "CIdtInfWrapper.head");
        print4x(this->head, this->len * this->size, caption);
    }
}

// sub_1001D120
CIdtInfWrapper *CIdtInfWrapper::init(LPCTDLLIDTINF idtInf)
{
    this->init(idtInf->head, idtInf->len, idtInf->num);
    this->pIDT_1407 = NULL;
    this->initData();
    this->initIdtnoIndexes();
    return this;
};

// sub_1001DE10
CIdtInfWrapper *CIdtInfWrapper::init(TDLLIDTListItem *head, int32_t len, int32_t *num)
{
    this->head = (LPVOID)head;
    this->size = sizeof(TDLLIDTListItem);
    this->len = len;
    this->tail = 0;
    this->needFreeHead = false;
    this->num = num;
    return this;
};

// sub_1001F509
void *CIdtInfWrapper::initData()
{
    void *result;
    int32_t i;

    result = NULL;
    if (strcmp(Str1, Str2) < 0)
    {
        this->pIDT_1407 = (TDLLIDTListItem_1407 *)this->head;
        this->head = new TDLLIDTListItem[this->len];
        memset(this->head, 0, sizeof(TDLLIDTListItem) * this->len);
        TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
        for (i = 0;; ++i)
        {
            result = this;
            if (i >= this->len)
            {
                break;
            }
            memcpy((void *)&pIDT[i], (const void *)(&this->pIDT_1407[i]), sizeof(TDLLIDTListItem_1407));
        }
    }
    return result;
};

// sub_1001D1A0
void *CIdtInfWrapper::initIdtnoIndexes()
{
    void *result;
    this->timeOfs = 0.0;
    this->qualitMode = 0;
    this->timeWindow = 0;
    this->refEnabled = false;
    this->istdAsRef = 0;
    this->based = 0;
    this->byCalib = false;
    this->pTypeExInf = NULL;
    this->validCount = 0;
    if (*(this->num) <= 0)
    {
        result = (void *)&(this->head);
        this->idtnoIndexes = NULL;
    }
    else
    {
        this->idtnoIndexes = new int32_t[*(this->num)];
        result = memset(this->idtnoIndexes, 0, sizeof(int32_t) * *(this->num));
    }
    return result;
};

// sub_1001B1C0
void CIdtInfWrapper::setBased(int32_t based)
{
    this->based = based;
};

// sub_1001D380
CBaseWrapper *CIdtInfWrapper::close(char flag)
{
    this->close();
    if (flag & 1)
    {
        delete this;
    }
    return this;
};

// sub_1001D3B0
CBaseWrapper *CIdtInfWrapper::close()
{
    int32_t i;

    this->clearTypeExInf();
    this->deleteIndexes();
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    if (this->head && this->pIDT_1407)
    {
        for (i = 0; i < this->len; ++i)
        {
            memcpy((void *)(&this->pIDT_1407[i]), (const void *)&pIDT[i], sizeof(TDLLIDTListItem_1407));
        }
        delete (int32_t *)this->head;
    }
    return this->close_();
};

// sub_1001D470
CIdtInfWrapper *CIdtInfWrapper::clearTypeExInf()
{
    if (this->pTypeExInf)
    {
        delete[] this->pTypeExInf;
        this->pTypeExInf = NULL;
    }
    this->validCount = 0;
    return this;
};

// sub_1001D4B0
void CIdtInfWrapper::deleteIndexes()
{
    if (this->idtnoIndexes)
    {
        delete[] this->idtnoIndexes;
        this->idtnoIndexes = NULL;
    }
}

// sub_1001FAE1
int32_t CIdtInfWrapper::getNextIndex(int32_t idx)
{
    int32_t result;

    if (this->num && *this->num > idx)
    {
        result = idx + 1;
    }
    else
    {
        result = 0;
    }
    return result;
}

// sub_1001AF70
char *CIdtInfWrapper::getIdtName(int32_t idx)
{
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    return pIDT[idx].Name;
}

// sub_1001FF25
int32_t CIdtInfWrapper::setTypeExInf()
{
    int32_t i;
    int32_t validNo;

    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    this->clearTypeExInf();
    if (this->refEnabled)
    {
        validNo = 0;
        this->validCount = this->fetchFirstTypeExNo(&validNo);
        if (this->validCount > 0)
        {
            this->pTypeExInf = new TypeExInf[this->validCount];
            memset((void *)this->pTypeExInf, 0, sizeof(TypeExInf) * this->validCount);
            this->pTypeExInf->validNo = validNo;
            this->pTypeExInf->Time = pIDT[validNo - 1].Time;
            this->pTypeExInf->band = pIDT[validNo - 1].band;
            this->pTypeExInf->RTime = 0.0;
            for (i = 1; i < this->validCount; ++i)
            {
                validNo = this->fetchNextTypeExNo(validNo, &this->pTypeExInf[i].Time, &this->pTypeExInf[i].band);
                this->pTypeExInf[i].validNo = validNo;
            }
            qsort(this->pTypeExInf, this->validCount, sizeof(TypeExInf), compareSecondDouble);
        }
    }
    return this->validCount;
}

// sub_1001FDC3
int32_t CIdtInfWrapper::fetchFirstTypeExNo(int32_t *firstValidNo)
{
    int32_t validNo;
    int32_t cnt;
    int32_t i;

    cnt = 0;
    validNo = 0;
    for (i = 0; i < *this->num; ++i)
    {
        if (this->checkTypeEx(i))
        {
            if (!validNo)
            {
                validNo = i + 1;
            }
            ++cnt;
        }
    }
    if (firstValidNo)
    {
        *firstValidNo = validNo;
    }
    return cnt;
}

// sub_1001FD24
int32_t CIdtInfWrapper::checkTypeEx(int32_t idx)
{
    int32_t typeEx;
    int32_t result;

    if (idx < 0 || idx >= *this->num)
    {
        return false;
    }

    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    typeEx = pIDT[idx].TypeEx;
    if (this->istdAsRef)
    {
        result = typeEx == 1 || this->checkStdNo(idx);
    }
    else
    {
        result = typeEx == 2 || typeEx == 6;
    }
    return result;
}

// sub_1001AB70
int32_t CIdtInfWrapper::checkStdNo(int32_t idx)
{
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    return pIDT[idx].istdNoSelf > 0 && !pIDT[idx].istdNoUsed;
}

// sub_1001FE59
int32_t CIdtInfWrapper::fetchNextTypeExNo(int32_t prevNo, double *time, double *band)
{
    int32_t i;
    int32_t nextIdx;

    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;

    if (prevNo < 0 || prevNo >= *this->num)
    {
        return 0;
    }
    nextIdx = -1;
    for (i = prevNo; i < *this->num; ++i)
    {
        if (this->checkTypeEx(i))
        {
            nextIdx = i;
            break;
        }
    }
    if (time)
    {
        if (nextIdx < 0)
        {
            *time = 0.0;
        }
        else
        {
            *time = pIDT[nextIdx].Time;
        }
        if (nextIdx < 0)
        {
            *band = 0.0;
        }
        else
        {
            *band = pIDT[nextIdx].band;
        }
    }
    return nextIdx + 1;
}

// sub_1001AEF0
int32_t CIdtInfWrapper::getValidNo(int32_t idx)
{
    int32_t result;

    if (idx >= 0 && idx < this->validCount)
    {
        result = this->pTypeExInf[idx].validNo;
    }
    else
    {
        result = 0;
    }
    return result;
}

// sub_1001F5C1
double CIdtInfWrapper::getIdtTimeAndBaseBand(int32_t idx, int32_t *basedOn, double *idtBand)
{
    int32_t bSelf;
    int32_t typeEx;
    double idtTime;
    double band;
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;

    idtTime = 0.0;
    if (idx >= 0 && idx < *this->num)
    {
        idtTime = pIDT[idx].Time;
        if (this->qualitMode == 1 && this->timeWindow > 0.0)
        {
            band = idtTime * this->timeWindow / 100.0;
        }
        else
        {
            band = pIDT[idx].band;
        }
        typeEx = pIDT[idx].TypeEx;
        if (this->getIsdtNoSelf(idx) || typeEx == 1 || (this->refEnabled && (typeEx == 2 || typeEx == 6)))
        {
            *basedOn = pIDT[idx].basedOn;
            if (*basedOn < 0 || *basedOn > 1)
            {
                *basedOn = this->based;
            }
        }
        else
        {
            *basedOn = -1;
        }
        if ((!this->qualitMode || this->qualitMode == 1) && fabs(this->timeOfs) > 1.0e-30)
        {
            idtTime = idtTime + this->timeOfs;
        }
        if (this->refEnabled)
        {
            bSelf = 0;
            if (this->istdAsRef && (this->getIsdtNoSelf(idx) || typeEx == 1))
            {
                bSelf = 1;
            }
            else if (typeEx == 2 || typeEx == 6)
            {
                bSelf = 1;
            }
            if (!bSelf)
            {
                idtTime = this->ajustRTime(idtTime);
            }
        }
    }
    else
    {
        *basedOn = -1;
        band = 0.0;
    }
    if (idtBand)
    {
        *idtBand = band;
    }
    return idtTime;
}

// sub_10024E90
int32_t CIdtInfWrapper::getIsdtNoSelf(int32_t idx)
{
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    return pIDT[idx].istdNoSelf;
}

// sub_100202CC
double CIdtInfWrapper::ajustRTime(double timeThreshold)
{
    double result;
    double currentRTime;
    double prevRTime;
    int32_t i;
    double currentTime;
    double prevTime;
    int32_t outIdx;
    TypeExInf *pType = (TypeExInf *)this->pTypeExInf;

    if (!this->validCount || !this->refEnabled)
    {
        return timeThreshold;
    }
    outIdx = -1;
    for (i = 0; i < this->validCount; ++i)
    {
        if (pType[i].Time > 0.0 && pType[i].Time > timeThreshold)
        {
            outIdx = i;
            break;
        }
    }
    if (!outIdx)
    {
        return timeThreshold * pType[0].RTime / pType[0].Time;
    }
    if (outIdx < 0)
    {
        return timeThreshold * pType[this->validCount - 1].RTime / pType[this->validCount - 1].Time;
    }
    prevTime = pType[outIdx - 1].Time;
    prevRTime = pType[outIdx - 1].RTime;
    currentTime = pType[outIdx].Time;
    currentRTime = pType[outIdx].RTime;
    if (currentTime == prevTime)
    {
        result = (prevRTime + currentRTime) * timeThreshold / 2.0 / prevTime;
    }
    else
    {
        result = (timeThreshold - prevTime) * (currentRTime - prevRTime) / (currentTime - prevTime) + prevRTime;
    }
    return result;
}

// sub_1001AF30
char CIdtInfWrapper::setTypeExRTime(int32_t idx, double rtime)
{
    if (idx < 0 || idx >= this->validCount)
    {
        return false;
    }
    this->pTypeExInf[idx].RTime = rtime;
    return true;
}

// sub_1001AEB0
void CIdtInfWrapper::clearIndexes()
{
    if (this->idtnoIndexes)
    {
        memset((void *)this->idtnoIndexes, 0, sizeof(int32_t) * *this->num);
    }
}

// sub_1001F7AA
int32_t CIdtInfWrapper::getNextIndexNearCenter(double resRTime, double tLeftOffs, double tRightOffs, int32_t idx)
{
    int32_t searchIdx;
    int32_t centerIdx = 0;
    double idtRTime;
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;

    if (idx < 0 || idx >= *this->num)
    {
        return 0;
    }
    if ((!this->qualitMode || this->qualitMode == 1) && fabs(this->timeOfs) > 1.0e-30)
    {
        resRTime = resRTime - this->timeOfs;
    }
    idtRTime = this->normalizeRTime(resRTime);
    if (abs(resRTime - 5.276667) < 0.001)
    {
        println("centerIdx = %d   idtRTime=%f", centerIdx, idtRTime);
    }
    centerIdx = this->getIdtIndexWrapTCenter(idx, resRTime, tLeftOffs, tRightOffs, idtRTime, tLeftOffs, tRightOffs);
    if (this->byCalib && centerIdx >= 0 && pIDT[centerIdx].weight < 1.0e-30)
    {
        searchIdx = centerIdx;
        while (1)
        {
            searchIdx = this->getIdtIndexWrapTCenter(searchIdx + 1, resRTime, tLeftOffs, tRightOffs, idtRTime,
                                                     tLeftOffs, tRightOffs);
            if (abs(resRTime - 5.276667) < 0.001)
            {
                println("searchIdx = %d pIDT[searchIdx].name,time,band,weight=%s,%f,%f,%f", searchIdx,
                        pIDT[searchIdx].Name, pIDT[searchIdx].Time, pIDT[searchIdx].band,
                        pIDT[searchIdx].weight);
                println("sizeOf TDLLIDTListItem = %d", sizeof(TDLLIDTListItem));
            }
            if (searchIdx >= 0 && pIDT[searchIdx].weight >= 1.0e-30)
            {
                break;
            }
            if (searchIdx < 0 || pIDT[searchIdx].weight >= 1.0e-30)
            {
                return centerIdx + 1;
            }
        }
        centerIdx = searchIdx;
    }
    return centerIdx + 1;
}

// sub_10020087
double CIdtInfWrapper::normalizeRTime(double resRTime)
{
    double currRTime;
    double currTime;
    double prevRTime;
    double prevTime;
    double idtRTime;
    double normRTime;
    int32_t i;
    int32_t outIdx;
    TypeExInf *pType = (TypeExInf *)this->pTypeExInf;

    if (!this->validCount || !this->refEnabled)
    {
        return resRTime;
    }
    normRTime = resRTime;
    outIdx = -1;
    for (i = 0; i < this->validCount; ++i)
    {
        idtRTime = pType[i].RTime;
        if (idtRTime > 0.0 && resRTime < idtRTime)
        {
            outIdx = i;
            break;
        }
    }
    if (outIdx)
    {
        if (outIdx >= 0)
        {
            prevTime = pType[outIdx - 1].Time;
            prevRTime = pType[outIdx - 1].RTime;
            currTime = pType[outIdx].Time;
            currRTime = pType[outIdx].RTime;
            if (currRTime == prevRTime)
            {
                normRTime = (prevTime + currTime) * resRTime / 2.0 / prevRTime;
            }
            else
            {
                normRTime = (resRTime - prevRTime) * (currTime - prevTime) / (currRTime - prevRTime) + prevTime;
            }
        }
        else
        {
            if (pType[this->validCount - 1].RTime > 0.0)
            {
                normRTime = resRTime * pType[this->validCount - 1].Time / pType[this->validCount - 1].RTime;
            }
        }
    }
    else
    {
        if (pType[0].RTime > 0.0)
        {
            normRTime = resRTime * pType[0].Time / pType[0].RTime;
        }
    }
    return normRTime;
}

// sub_1001F959
int32_t CIdtInfWrapper::getIdtIndexWrapTCenter(int32_t idx, double resRTime, double a4, double a5, double tCenter,
                                               double tLeftOffs, double tRightOffs)
{
    double time;
    double band;
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    while (idx < *this->num)
    {
        time = pIDT[idx].Time;
        band = pIDT[idx].band;
        if (band <= time)
        {
            if (this->qualitMode == 1 && this->timeWindow > 0.0)
            {
                band = pIDT[idx].Time * this->timeWindow / 100.0;
            }
            if (band > 0.0 && time - band <= tCenter && time + band >= tCenter)
            {
                return idx;
            }
            if (a4 > 0.0 && a5 > 0.0 && tCenter - tLeftOffs <= time && tCenter + tRightOffs >= time)
            {
                return idx;
            }
        }
        else if (resRTime > time && resRTime < band)
        {
            return idx;
        }
        ++idx;
    }
    return -1;
}

// sub_1001B080
int32_t CIdtInfWrapper::getIdtnoIndex(int32_t idtno)
{
    int32_t result;

    result = 0;
    if (idtno >= 0 && idtno < *this->num && this->idtnoIndexes)
    {
        result = this->idtnoIndexes[idtno];
    }
    return result;
}

// sub_1001ABC0
int32_t CIdtInfWrapper::isBandExceedTime(int32_t idx)
{
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    return pIDT[idx].band > pIDT[idx].Time;
}

// sub_1001AFF0
CIdtInfWrapper *CIdtInfWrapper::setIdtnoIndex(int32_t idtno, int32_t idx)
{
    if (idtno >= 0)
    {
        if (idtno < *this->num)
        {
            if (this->idtnoIndexes)
            {
                this->idtnoIndexes[idtno] = idx;
            }
        }
    }
    return this;
}

// sub_1001FB10
int32_t CIdtInfWrapper::fetchStdnoSelfArray(int32_t **stdnoSelfArray)
{
    int32_t idx;
    int32_t counter;
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;

    memset(gStdnoSelf, 0, sizeof(gStdnoSelf));
    idx = 0;
    counter = 0;
    while (idx < *this->num)
    {
        if (this->checkStdNo(idx))
        {
            gStdnoSelf[counter++] = pIDT[idx].istdNoSelf;
            if (counter >= 16)
            {
                break;
            }
        }
        ++idx;
    }
    *stdnoSelfArray = counter != 0 ? gStdnoSelf : NULL;
    return counter;
}

// sub_1001F46B
int32_t CIdtInfWrapper::clearCorrectFactor()
{
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    int32_t i;
    int32_t result;
    for (i = 0;; ++i)
    {
        result = i;
        if (i >= *this->num)
        {
            break;
        }
        pIDT[i].f0 = 0;
        pIDT[i].f1 = 0;
        pIDT[i].f2 = 0;
        pIDT[i].f3 = 0;
        pIDT[i].r = 0;
    }
    return result;
}

// sub_1001F3E5
int32_t CIdtInfWrapper::setCorrectFactor(int32_t idx, double r, double f0, double f1, double f2, double f3)
{
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    int32_t result;

    pIDT[idx].r = (float)r;
    pIDT[idx].f0 = (float)f0;
    pIDT[idx].f1 = (float)f1;
    pIDT[idx].f2 = (float)f2;
    pIDT[idx].f3 = (float)f3;
    result = sizeof(TDLLIDTListItem) * idx;
    return result;
}

// sub_1001B130
int32_t CIdtInfWrapper::isStdnoUsed(int32_t idx)
{
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;
    return !pIDT[idx].istdNoSelf && pIDT[idx].istdNoUsed > 0;
}

// sub_1001AD00
int32_t CIdtInfWrapper::getStdnoUsed(int32_t idx)
{
    int32_t i;
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;

    if (idx >= 0)
    {
        return pIDT[idx].istdNoUsed;
    }
    for (i = 0; i < *this->num; ++i)
    {
        if (this->checkStdNo(i))
        {
            return i + 1;
        }
    }
    return 0;
}

// sub_100204F1
void CIdtInfWrapper::calcSegCalibItem(int32_t idx, int32_t segCalibCount, double *x, double *y, int32_t segCalibMode,
                                      int32_t mode)
{
    int32_t i;
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;

    if (this->head)
    {
        if (this->num)
        {
            if (idx < *this->num)
            {
                if (segCalibCount > 16)
                {
                    segCalibCount = 16;
                }
                pIDT[idx].SegCalibMode = segCalibMode;
                pIDT[idx].SegCalibCount = segCalibCount;
                for (i = 0; i < segCalibCount; ++i)
                {
                    TSegCalibItem *pSeg = &(pIDT[idx].SegCalibItems[i]);
                    pSeg->x = x[i];
                    if (i)
                    {
                        if (x[i] == x[i - 1])
                        {
                            pSeg->a = 0.0;
                        }
                        else
                        {
                            pSeg->a = (y[i] - y[i - 1]) / (x[i] - x[i - 1]);
                        }
                        pSeg->b = y[i] - pSeg->a * x[i];
                    }
                    else if (mode == 4)
                    {
                        pSeg->a = pIDT[idx].f1;
                        pSeg->b = *y - pSeg->a * x[0];
                    }
                    else
                    {
                        if (*x <= 0.0)
                        {
                            pSeg->a = 0.0;
                        }
                        else
                        {
                            pSeg->a = *y / *x;
                        }
                        pSeg->b = 0;
                    }
                }
            }
        }
    }
}

// sub_1001B0D0
int32_t CIdtInfWrapper::isBaseOnArea(int32_t idx, int32_t placeholder)
{
    int32_t basedOn;
    TDLLIDTListItem *pIDT = (TDLLIDTListItem *)this->head;

    if (idx < 0 || idx >= *this->num)
    {
        return placeholder == 0;
    }
    basedOn = pIDT[idx].basedOn;
    if (basedOn < 0 || basedOn > 1)
    {
        basedOn = placeholder;
    }
    return basedOn == 0;
}

// sub_1001DC20
int32_t CIdtInfWrapper::setMiscellaneous(TMiscellaneous *wParam, int32_t byCalib)
{
    if (wParam)
    {
        this->qualitMode = wParam->QualitMode;
        this->refEnabled = wParam->RefEnabled;
        this->istdAsRef = wParam->IstdAsRef;
        this->timeOfs = wParam->IdtTimeOfs;
        this->timeWindow = wParam->IdtWindow;
    }
    else
    {
        this->qualitMode = 0;
        this->refEnabled = false;
        this->istdAsRef = false;
        this->timeOfs = 0.0;
        this->timeWindow = 0.0;
    }
    this->byCalib = byCalib;
    return true;
}
